﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Arroguella.Entities
{
    /// <summary>
    /// The StorageEntityComponent allows an entity to have its own inventory / storage system.
    /// It has a set weight limit (in kg).
    /// </summary>
    public class StorageEntityComponent : EntityComponent
    {
        #region Constructor

        public StorageEntityComponent(float weightLimit)
        {
            WeightLimit = weightLimit;
            CurrentWeight = 0f;
            InventoryByName = new Dictionary<string, Entity>();
            EntityQuantities = new Dictionary<string, int>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Attempts to add an Entity to the Inventory.
        /// If this type of Entity already exists, we increase its quantity.
        /// </summary>
        /// <param name="entity">The entity to be added</param>
        /// <returns>True if we were successful, false otherwise.</returns>
        public bool Add(Entity entity)
        {
            // Check to make sure we can add the entity, first
            if (CurrentWeight + entity.Weight > WeightLimit)
            {
                return false;
            }

            CurrentWeight += entity.Weight;

            if (EntityQuantities.ContainsKey(entity.Name))
            {
                EntityQuantities[entity.Name] += 1;
            }
            else
            {
                InventoryByName.Add(entity.Name, entity);
                EntityQuantities.Add(entity.Name, 1);
            }

            return true;
        }

        /// <summary>
        /// Tries to get a reference to the Entity in Inventory.
        /// This does NOT remove the Entity from Inventory.
        /// </summary>
        public void TryGetEntity(string name, out Entity entity)
        {
            if(InventoryByName.ContainsKey(name) && EntityQuantities.ContainsKey(name))
            {
                entity = InventoryByName[name];
            }
            else
            {
                entity = null;
            }
        }

        /// <summary>
        /// Removes an Entity from Inventory.
        /// If this reduces that Entity's quantity to 0,
        /// we remove all references to it here. 
        /// </summary>
        /// <param name="name">The name of the Entity to be removed.</param>
        /// <returns>The Entity specified.</returns>
        public Entity Remove(string name)
        {
            if (EntityQuantities.ContainsKey(name))
            {
                Entity entity = InventoryByName[name];
                EntityQuantities[name] -= 1;
                CurrentWeight -= entity.Weight;

                if (EntityQuantities[name] == 0)
                {
                    EntityQuantities.Remove(name);
                    InventoryByName.Remove(name);
                }

                return entity;
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region Properties

        public float WeightLimit { get; private set; }

        public float CurrentWeight { get; private set; }

        /// <summary>
        /// A mapping of the entity names to the entities themselves.
        /// This provides for easy lookup.
        /// </summary>
        public Dictionary<string, Entity> InventoryByName { get; private set; }

        /// <summary>
        /// A mapping of the entity names to their corresponding quantities.
        /// Any Entity without a unique name may be "stacked" indefinitely.
        /// </summary>
        public Dictionary<string, int> EntityQuantities { get; private set; }

        #endregion
    }
}
